package com.example.drive.db

import android.database.Cursor
import androidx.core.database.*
import androidx.room.*
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.sqlite.db.SupportSQLiteQuery

/**
 * 数据库访问对象基类,子类必须实现initTableName()方法
 *
 * [T]数据库对应的实体类的类型
 */
abstract class BaseDao<T> {
    // 表名
    val tableName: String by lazy {
        initTableName()
    }

    /**
     * 初始化表名,子类必须实现此方法
     */
    abstract fun initTableName(): String

    /**
     * 插入一个
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    abstract fun insert(entity: T): Long

    /**
     * 插入多个
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    abstract fun insertAll(list: List<T>): LongArray

    /**
     * 删除一个
     */
    @Delete
    abstract fun delete(entity: T)

    /**
     * 删除全部
     */
    fun clear(): Int = rawQuery(SimpleSQLiteQuery("DELETE FROM $tableName"))

    /**
     * 更新一个
     */
    @Update
    abstract fun update(entity: T): Int

    /**
     * 更新全部
     */
    fun replaceAll(list: List<T>): Int {
        clear()
        return insertAll(list).size
    }

    /**
     * 根据field和value删除
     *
     * [args] 比较的条件
     */
    fun delete(args: CompareCondition): Int {
        val sql = "DELETE FROM $tableName ${args.condition}"
        val query = SimpleSQLiteQuery(sql, arrayOf(args.value))
        return rawQuery(query)
    }

    /**
     * 根据field和value查询,比较常用
     *
     * [args] 比较的条件
     */
    fun query(args: CompareCondition): List<T>? {
        val sql = "SELECT * FROM $tableName ${args.condition}"
        val query = SimpleSQLiteQuery(sql, arrayOf(args.value))
        return rawQueryList(query)
    }

    /**
     * 按条件查询
     *
     * [args] 查询条件
     */
    fun queryByCondition(args: BaseCondition): List<T>? {
        val sql = "SELECT * FROM $tableName ${args.condition}"
        println("queryByCondition,sql:$sql")
        return rawQueryList(SimpleSQLiteQuery(sql))
    }

    /**
     * 删除多个
     *
     * [args] 删除条件
     */
    fun deleteMore(args: InCondition): Int? {
        val sql = "DELETE FROM $tableName ${args.condition}"
        println("deleteMore,sql:$sql")
        return rawQuery(SimpleSQLiteQuery(sql))
    }

    /**
     * 查询多个,比较常用
     *
     * [args] 查询条件
     */
    fun queryMore(args: InCondition): List<T>? {
        val sql = "SELECT * FROM $tableName ${args.condition}"
        println("queryMore,sql:$sql")
        return rawQueryList(SimpleSQLiteQuery(sql))
    }

    /**
     * 按列查询(SELECT field1,field2 FROM tableName WHERE 范围)
     *
     * [R] fields只有一列,传入[String]or[Short]or[Int]or[Float]or[Double]or[ByteArray],fields有多列,传入[T]
     * [fields] 查询哪几列
     * [compareCondition] 查询范围
     *
     * @return List<R>
     */
    inline fun <reified R> queryByCompareCondition(
        fields: Set<String>,
        compareCondition: CompareCondition? = null
    ): List<R?>? {
        if (fields.isEmpty()) {
            return null
        }
        // 末尾的空格不能少
        val select = StringBuilder("SELECT ${fields.fieldsToArgs()} FROM $tableName ")
        var array: Array<Any>? = null
        compareCondition?.let {
            select.append(it.condition)
            array = arrayOf(compareCondition.value)
        }
        println("sql:$select")
        val query = SimpleSQLiteQuery(select.toString(), array)
        return if (fields.size == 1) {
            rawQueryCursor(query)?.parse(fields.elementAt(0))
        } else {
            rawQueryList(query) as? List<R>?
        }
    }

    /**
     * 按列查询(SELECT field1,field2 FROM tableName WHERE 范围)
     *
     * [R] fields只有一列,传入[String]or[Short]or[Int]or[Float]or[Double]or[ByteArray],fields有多列,传入[T]
     * [fields] 查询哪几列
     * [inCondition] 查询范围
     *
     * @return List<R>
     */
    inline fun <reified R> queryByInCondition(
        fields: Set<String>,
        inCondition: InCondition? = null
    ): List<R?>? {
        if (fields.isEmpty()) {
            return null
        }
        // 末尾的空格不能少
        val select = StringBuilder("SELECT ${fields.fieldsToArgs()} FROM $tableName ")
        inCondition?.let {
            select.append(it.condition)
        }
        println("sql:$select")
        val query = SimpleSQLiteQuery(select.toString(), null)
        return if (fields.size == 1) {
            rawQueryCursor(query)?.parse(fields.elementAt(0))
        } else {
            rawQueryList(query) as? List<R?>?
        }
    }

    /**
     * 查询单列返回基本类型,查询多列返回List<T>
     */
    inline fun <reified R> Cursor.parse(field: String): List<R?> {
        val list = mutableListOf<R?>()
        use {
            val index = getColumnIndex(field)
            while (moveToNext()) {
                when (R::class) {
                    String::class -> list.add(it.getStringOrNull(index) as? R)
                    Short::class -> list.add(it.getShortOrNull(index) as? R)
                    Int::class -> list.add(it.getIntOrNull(index) as? R)
                    Long::class -> list.add(it.getLongOrNull(index) as? R)
                    Float::class -> list.add(it.getFloatOrNull(index) as? R)
                    Double::class -> list.add(it.getDoubleOrNull(index) as? R)
                    ByteArray::class -> list.add(it.getBlobOrNull(index) as? R)
                    else -> println("查询单列,泛型参数不匹配")
                }
            }
        }
        return list
    }

    /**
     * 查询全部
     */
    fun queryAll(): List<T>? = rawQueryList(SimpleSQLiteQuery("SELECT * FROM $tableName"))

    /**
     * 查询数量
     */
    fun count(): Int = rawQuery(SimpleSQLiteQuery("SELECT COUNT(*) FROM $tableName"))

    /**
     * 多个字段用逗号拼接
     */
    fun Iterable<String>.fieldsToArgs(): String {
        val builder = StringBuilder()
        forEach {
            builder.append("$it,")
        }
        return builder.substring(0, builder.length - 1)
    }

    /**
     * 原始查询
     */
    @RawQuery
    abstract fun rawQuery(query: SupportSQLiteQuery): Int

    /**
     * 原始查询
     */
    @RawQuery
    abstract fun rawQueryCursor(query: SupportSQLiteQuery): Cursor?

    /**
     * 原始查询
     */
    @RawQuery
    abstract fun rawQueryList(query: SupportSQLiteQuery): List<T>?
}